﻿using com.yoozoo.gta.Gameplay.PVE;
using Gameplay.PVE;
using LogSystem;
using System;
using System.Collections.Generic;
using DestroyIt;
using UnityEditor;
using UnityEngine;
using Yoozoo.Core.Common;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.Liberty
{
    //[RequireComponent(typeof(SceneObjectLoadController))]
    public class LibertySceneManager : MonoBehaviour, IQualityListener
    {
        // 当前设备等级支持每帧处理的动态物体数量
        private static readonly Dictionary<QualityEnum, int> _AsyncDynamicObjectCount = 
            new Dictionary<QualityEnum, int>
            {
                { QualityEnum.Low, 3 },
                { QualityEnum.Medium, 3 },
                { QualityEnum.High, 4 },
                { QualityEnum.VeryHigh, 4 },
                { QualityEnum.Perfect, 5 },
            };
        // 当前设备等级支持每帧处理的NPC数量
        private static readonly Dictionary<QualityEnum, int> _AsyncNpcCount = 
            new Dictionary<QualityEnum, int>
            {
                { QualityEnum.Low, 1 },
                { QualityEnum.Medium, 1 },
                { QualityEnum.High, 1 },
                { QualityEnum.VeryHigh, 1 },
                { QualityEnum.Perfect, 1 },
            };
        // 当前设备等级支持每帧处理的车辆数量
        private static readonly Dictionary<QualityEnum, int> _AsyncCarCount = 
            new Dictionary<QualityEnum, int>
            {
                { QualityEnum.Low, 1 },
                { QualityEnum.Medium, 1 },
                { QualityEnum.High, 1 },
                { QualityEnum.VeryHigh, 1 },
                { QualityEnum.Perfect, 1 },
            };
        
        public Transform root;
        public Transform staticRoot;
        public Transform dynamicRoot;
        public Transform npcRoot;

        public SceneSeparateManagerData sceneSeparateData;
        public SceneSeparateManagerData birthData;

        public SceneDetectorBase sceneDetector;
        public SceneDetectorBase npcDetector;
        public SceneDetectorBase carBirthPointDetector;
        
        private SceneObjectLoadController _loadController;
        private SceneObjectLoadController _loadNpcController;
        private SceneObjectLoadController _loadCarController;
        private StaticSceneObjectController _staticSceneObjectController;

        private bool _init;

        private bool _pause;

        private bool _isInitDynamic;

        public static LibertySceneManager instance;
        public List<Destructible> GetComponentCachList = new List<Destructible>(4);

        public static bool hasSceneRootOffset = false;
        public static Vector3 sceneRootOffset = Vector3.zero;
        
        public SceneSeparateManagerData configData;
        
        public void DestoryDynamicObj(SceneObject obj)
        {
            _loadController?.CrashObject(obj,false);
        }

        public void CrashDynamicObj(SceneObject obj)
        {
            
        }
        void Awake()
        {
            instance = this;
            QualityManager.Inst.AddQualityListener(this);
        }

        void OnDestroy()
        {
            instance = null;
            QualityManager.Inst.RemoveQualityListener(this);
        }

        public static void RefreshDetectorImmediately(SceneDetectorBase sceneDetector)
        {
            if (!instance) return;
            if (sceneDetector == null) return;

            instance.AddDynamicObject();
            instance.sceneDetector = sceneDetector;
            if (instance._loadController != null)
            {
                instance._loadController.RefreshDetectorImmediately(sceneDetector);
            }

            if (instance._staticSceneObjectController != null)
            {
                instance._staticSceneObjectController.RefreshDetectorImmediately(sceneDetector);
            }
        }

        public static void RefreshNPCDetectorImmediately()
        {
            if (!instance) return;
            if (instance._loadNpcController != null && instance.npcDetector != null)
            {
                instance._loadNpcController.RefreshDetectorImmediately(instance.npcDetector);
            }
        }

        public static void DestroyAllDynamicObjects()
        {
            if (!instance) return;
            if (instance._loadController != null)
            {
                instance._loadController.UnloadAllDynamicObjects();
            }
        }

        public void UnloadAllDynamicObjects()
        {
            _loadController.UnloadAllDynamicObjects();
            ResObjectCacheManager.Dispose();
        }

        private bool isSurvivor = false;

        public void InitSurvivor(Action<SceneObjectInfo> beforeShow, Action<SceneObjectInfo,GameObject> afterShow,Action<SceneObjectInfo> onHide)
        {
            isSurvivor = true;
            foreach (var staticObject in configData._staticObjects)
            {
                staticObject.beforeShow = beforeShow;
                staticObject.afterShow = afterShow;
                staticObject.onHide = onHide;
            }

            foreach (var loadObject in configData._loadObjects)
            {
                loadObject.beforeShow = beforeShow;
                loadObject.afterShow = afterShow;
                loadObject.onHide = onHide;
            }
            Init(configData, null);
        }
        
        public void Init(
            SceneSeparateManagerData separateData,
            SceneSeparateManagerData birthPointData
            )
        {
            this.root = this.transform;
            this.staticRoot = new GameObject("StaticRoot").transform;
            this.staticRoot.parent = this.root;
            this.dynamicRoot = new GameObject("DynamicRoot").transform;
            this.dynamicRoot.parent = this.root;

            this.sceneSeparateData = separateData;
            
            _staticSceneObjectController = dynamicRoot.gameObject.AddComponent<StaticSceneObjectController>();
            _staticSceneObjectController.Init(
                separateData.bounds.center,
                separateData.bounds.size,
                1,
                separateData.treeType, 5, onEnter, onExit);

            foreach (var staticObject in sceneSeparateData._staticObjects)
            {
                staticObject.SetSceneSeparateManagerData(sceneSeparateData);
            }

            foreach (var loadObject in sceneSeparateData._loadObjects)
            {
                loadObject.SetSceneSeparateManagerData(sceneSeparateData);
            }

            this.birthData = birthPointData;
            
            _loadController = dynamicRoot.gameObject.AddComponent<SceneObjectLoadController>();
            _loadController.Init(
                separateData.bounds.center,
                separateData.bounds.size, 
                separateData.asyn,
                separateData.treeType);

            _loadNpcController = dynamicRoot.gameObject.AddComponent<SceneObjectLoadController>();
            _loadNpcController.Init(
                separateData.bounds.center,
                separateData.bounds.size, 
                separateData.asyn,
                separateData.treeType);

            _loadCarController = dynamicRoot.gameObject.AddComponent<SceneObjectLoadController>();
            _loadCarController.Init(
                separateData.bounds.center,
                separateData.bounds.size, 
                separateData.asyn,
                separateData.treeType);
            
            OnChangeQuality(QualityManager.Inst.CurrentQuality);
            
            GenerateStaticObjects();
            _init = true;
        }

        private void onExit(SceneObject sceneObject)
        {
            sceneObject.TargetObj.RemoveLightmapIndices();
        }

        private void onEnter(SceneObject sceneObject)
        {
            sceneObject.TargetObj.AddLightmapIndices();
        }

        public void AddDynamicObject()
        {
            if (_isInitDynamic) return;

            foreach (var sceneObjectInfo in sceneSeparateData._loadObjects)
            {
                if (sceneObjectInfo.SceneObjType != SceneObjType.StaticHqOnly)
                {
                    _loadController.AddSceneBlockObject(sceneObjectInfo);
                }
            }

            if (birthData)
            {
                for (int i = 0; i < birthData.npcPoints.Count; i++)
                {
                    if (birthData.npcPoints[i].npcType == 3 || 
                        birthData.npcPoints[i].npcType == 4) // 车辆生成点
                    {
                        _loadCarController.AddSceneBlockObject(birthData.npcPoints[i]);
                    }
                    else
                    {
                        _loadNpcController.AddSceneBlockObject(birthData.npcPoints[i]);
                    }
                
                }
            }
            _isInitDynamic = true;
        }

        public void ShowDynamicObjects(Vector3 center, float radius, Action callBack = null)
        {
            var sceneObjectInfos = new List<SceneObjectInfo>(200);
            foreach (var sceneObjectInfo in sceneSeparateData._loadObjects)
            {
                if (sceneObjectInfo != null)
                {
                    if (Vector3.Distance(sceneObjectInfo.Position, center) < radius)
                    {
                        sceneObjectInfos.Add(sceneObjectInfo);
                    }
                }
            }

            int dc = 0;
            foreach (var sceneObjectInfo in sceneObjectInfos)
            {
                sceneObjectInfo.OnShow(_loadController.transform, (obj) =>
                {
                    dc++;
                    if (dc == sceneObjectInfos.Count)
                    {
                        callBack?.Invoke();
                    }
                });
            }
            
        }

        public void SetSceneDetector(SceneDetectorBase detector)
        {
            this.sceneDetector = detector;
        }

        public void SetNpcDetector(SceneDetectorBase detector)
        {
            this.npcDetector = detector;
        }

        public void SetCarBirthPointDetector(SceneDetectorBase detector)
        {
            this.carBirthPointDetector = detector;
        }
        
        public void Pause()
        {
            _pause = true;
        }

        public void Resume()
        {
            _pause = false;
        }

        public void Dispose()
        {
            foreach (var sceneObjectInfo in sceneSeparateData._loadObjects)
            {
                sceneObjectInfo.OnHide();
            }

            foreach (var sceneObjectInfo in sceneSeparateData._staticObjects)
            {
                sceneObjectInfo.OnHide();
            }
        }
        
        private void GenerateStaticObjects()
        {
            foreach (var sceneObjectInfo in sceneSeparateData._staticObjects)
            {
                if (isSurvivor)
                {
                    _loadController.AddSceneBlockObject(sceneObjectInfo);
                }
                else
                {
                    sceneObjectInfo.OnShow(staticRoot);
                    _staticSceneObjectController.AddSceneObject(sceneObjectInfo);
                }
            }

            foreach (var sceneObjectInfo in sceneSeparateData._loadObjects)
            {
                if (sceneObjectInfo.SceneObjType == SceneObjType.StaticHqOnly)
                {
                    if (QualityManager.Inst.CurrentQuality > QualityEnum.High && !isSurvivor)
                    {
                        sceneObjectInfo.OnShow(staticRoot);
                        _staticSceneObjectController.AddSceneObject(sceneObjectInfo);
                    }
                    else
                    {
                        _loadController.AddSceneBlockObject(sceneObjectInfo);
                    }
                }
            }
        }
        
        private void Update()
        {
            if (!_init) return;
            if (_pause) return;
            
            if (sceneDetector)
            {
                _loadController.RefreshDetector(sceneDetector);
                _staticSceneObjectController.RefreshDetector(sceneDetector);
            }

            if (npcDetector)
            {
                _loadNpcController.RefreshDetector(npcDetector);
            }

            if (carBirthPointDetector)
            {
                _loadCarController.RefreshDetector(carBirthPointDetector);
            }

            if (useBlockBake)
            {
                UpdateLightmap();
            }
        }

        public void OnChangeQuality(QualityEnum quality)
        {
            if (_loadController)
            {
                int dynamicAsynCount = 1;
                _AsyncDynamicObjectCount.TryGetValue(quality, out dynamicAsynCount);
                _loadController.AsynCount = dynamicAsynCount;
            }

            if (_loadNpcController)
            {            
                int npcAsynCount = 1;
                _AsyncNpcCount.TryGetValue(quality, out npcAsynCount);
                _loadNpcController.AsynCount = npcAsynCount;
            }

            if (_loadCarController)
            {
                int carAsynCount = 1;
                _AsyncCarCount.TryGetValue(quality, out carAsynCount);
                _loadCarController.AsynCount = carAsynCount;
            }
        }

        public void ShowAllObjects(Transform parent)
        {
            #if UNITY_EDITOR
            foreach (var sceneObjectInfo in configData._loadObjects)
            {
                sceneObjectInfo.SetSceneSeparateManagerData(configData);
                var path = sceneObjectInfo.GetPrefabPath();
                var resource = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (resource)
                {
                    var obj = GameObject.Instantiate(resource);
                    obj.transform.parent = parent;
                    obj.transform.position = sceneObjectInfo.Position;
                    obj.transform.localEulerAngles = sceneObjectInfo.Rotation;
                    obj.transform.localScale = sceneObjectInfo.Size;
                }
            }
            
            foreach (var sceneObjectInfo in configData._staticObjects)
            {
                sceneObjectInfo.SetSceneSeparateManagerData(configData);
                var path = sceneObjectInfo.GetPrefabPath();
                var resource = AssetDatabase.LoadAssetAtPath<GameObject>(path);
                if (resource)
                {
                    var obj = GameObject.Instantiate(resource);
                    obj.transform.parent = parent;
                    obj.transform.position = sceneObjectInfo.Position;
                    obj.transform.localEulerAngles = sceneObjectInfo.Rotation;
                    obj.transform.localScale = sceneObjectInfo.Size;
                }
            }
            #endif
        }

        #region 管理Lightmap

        /// <summary>
        /// 是否分块烘焙，是的话Lightmap会很多，需要动态管理；否的话就全部加载
        /// </summary>
        private static bool useBlockBake;

        private static SceneRenderData sceneRenderData;

        private static LightmapData[] lightmaps;

        /// <summary>
        /// 用来加载LightmapColor/Dir, 同时也能用来判断是否正在加载
        /// </summary>
        private static ResLoader[] lightmapLoaders;

        /// <summary>
        /// Lightmap使用次数，到0就卸载
        /// </summary>
        private static int[] lightmapCounts;

        /// <summary>
        /// 0: 没加载; 1: 加载中; 2: 已加载
        /// </summary>
        private static int[] lightmapStates;

        private static Texture2D defaultSquareTexture;

        private readonly static string defaultSquarePath = "Assets/ResourcesAssets/Texture/City/DefaultLightmapSquare.png";

        public static void InitializeLightmap(SceneRenderData renderData)
        {
            useBlockBake = false;
            sceneRenderData = null;
            if (renderData == null)
                return;

            sceneRenderData = renderData;
            useBlockBake = renderData.useBlockBake;
            if (useBlockBake)
            {
                if (defaultSquareTexture)
                {
                    ApplyLightmaps();
                }
                else
                {
                    UMTResource.LoadAsset(defaultSquarePath, (assetName, asset, duration, data) =>
                    {
                        defaultSquareTexture = (Texture2D)asset;
                        if (defaultSquareTexture)
                            ApplyLightmaps();
                    });
                }
            }
        }

        private static void ApplyLightmaps()
        {
            int count = sceneRenderData.lightMapColorPath.Count;
            lightmaps = new LightmapData[count];
            lightmapLoaders = new ResLoader[count];
            lightmapCounts = new int[count];
            lightmapStates = new int[count];
            for (int i = 0; i < count; i++)
            {
                lightmaps[i] = new LightmapData
                {
                    lightmapColor = defaultSquareTexture,
                    lightmapDir = defaultSquareTexture
                };
                lightmapLoaders[i] = null;
                lightmapCounts[i] = 0;
                lightmapStates[i] = 0;
            }

            LightmapSettings.lightmaps = lightmaps;
            LightmapSettings.lightmapsMode = LightmapsMode.CombinedDirectional;
        }

        /// <summary>
        /// 用到了某个LightmapIndex
        /// </summary>
        /// <param name="i"></param>
        public static void EnableLightmapIndex(int i)
        {
            if (i < 0)
                return;

            if (lightmaps == null)
                return;

            if (i >= lightmaps.Length)
            {
                Debug.LogErrorFormat(LogModule.LibertyScene, "i >= lightmaps.Length");
                return;
            }

            lightmapCounts[i]++;
        }

        /// <summary>
        /// 不再用某个LightmapIndex
        /// </summary>
        /// <param name="i"></param>
        public static void DisableLightmapIndex(int i)
        {
            if (i < 0)
                return;

            if (lightmaps == null)
                return;

            if (i >= lightmaps.Length)
            {
                Debug.LogErrorFormat(LogModule.LibertyScene, "i >= lightmaps.Length");
                return;
            }

            lightmapCounts[i]--;

            if (lightmapCounts[i] < 0)
            {
                Debug.LogErrorFormat(LogModule.LibertyScene, "lightmapCounts[i] < 0");
                lightmapCounts[i] = 0;
            }
        }


        public static void UpdateLightmap()
        {
            if (lightmapCounts == null)
                return;

            for (int i = 0; i < lightmapCounts.Length; i++)
            {
                var lightmapIndex = i;

                if (lightmapCounts[lightmapIndex] > 0 && lightmapStates[lightmapIndex] == 0)
                {
                    // 加载
                    Debug.Log(LogModule.LibertyScene, $"添加Lightmap: {lightmapIndex}");
                    lightmapStates[lightmapIndex] = 1;
                    var resLoader = ResLoader.Alloc();
                    lightmapLoaders[lightmapIndex] = resLoader;
                    resLoader.Add2Load(sceneRenderData.lightMapColorPath[lightmapIndex], (success, assetName, asset) =>
                    {
                        if (asset is Texture2D texture)
                        {
                            lightmaps[lightmapIndex].lightmapColor = texture;
                        }
                    });

                    resLoader.Add2Load(sceneRenderData.lightMapDirPath[lightmapIndex], (success, assetName, asset) =>
                    {
                        if (asset is Texture2D texture)
                        {
                            lightmaps[lightmapIndex].lightmapDir = texture;
                        }
                    });

                    resLoader.Load(() =>
                    {
                        LightmapSettings.lightmaps = lightmaps;

                        if (lightmapLoaders[lightmapIndex] != null)
                            lightmapLoaders[lightmapIndex].Recycle2Cache();
                        lightmapLoaders[lightmapIndex] = null;
                        lightmapStates[lightmapIndex] = 2;
                    });
                } 
                else if (lightmapCounts[lightmapIndex] == 0 && lightmapStates[lightmapIndex] == 2)
                {
                    // 卸载
                    Debug.Log(LogModule.LibertyScene, $"卸载Lightmap: {lightmapIndex}");
                    lightmapStates[lightmapIndex] = 0;
                    if(lightmaps[lightmapIndex].lightmapColor)
                    {
                        UMTResource.UnloadAsset(lightmaps[lightmapIndex].lightmapColor);
                        lightmaps[lightmapIndex].lightmapColor = defaultSquareTexture;
                    }

                    if (lightmaps[lightmapIndex].lightmapDir)
                    {
                        UMTResource.UnloadAsset(lightmaps[lightmapIndex].lightmapDir);
                        lightmaps[lightmapIndex].lightmapDir = defaultSquareTexture;
                    }

                    LightmapSettings.lightmaps = lightmaps;
                }
            }
        }

        public void SetSync(bool sync)
        {
            _loadController?.SetSync(sync);
        }
        #endregion
    }
}
